﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using M3G;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;

namespace Sample_001_Simple {
    class Program : GameWindow {

        Graphics3D g3d;
        World      wld;

        public Program ()
            : base (800, 600, GraphicsMode.Default, "M3G Sample") {
            VSync = VSyncMode.On;
        }

        protected override void OnLoad (EventArgs e) {
            base.OnLoad (e);

            g3d = Graphics3D.GetInstance ();
            wld = new World ();

            var bg = new Background ();
            bg.SetColor (0xff0000ff);
            wld.SetBackground (bg);

            var cam = new Camera ();
            cam.SetTranslation (0, 0, 5);
            cam.SetPerspective (45.0f, 1.333f, 0.1f, 100);

            wld.AddChild (cam);
            wld.SetActiveCamera (cam);

            var positions = new VertexArray (4, 3, ArrayType.Float);
            var colors    = new VertexArray (4, 3, ArrayType.Byte);
            positions.Set (0, 4, new float[]{ 0.5f,-0.5f, 0,
                                              0.5f, 0.5f, 0,
                                             -0.5f,-0.5f, 0, 
                                             -0.5f, 0.5f, 0});
            colors.Set (0, 4, new byte[]{255, 0, 0,
                                         0, 255, 0,
                                         0, 0, 255,
                                         255, 255, 255});
            var vbuf  = new VertexBuffer ();
            var scale = 1.0f;
            var bias  = new float[] { 0, 0, 0 };
            vbuf.SetPositions (positions, scale, bias);
            vbuf.SetColors (colors);

            var strips  = new int[] { 4 };
            var indices = new int[] { 0, 1, 2, 3 };
            var ibuf    = new IndexBuffer (PrimitiveType.Triangles, strips, indices);


            var app = new ShaderAppearance ();

            var fragShader = new FragmentShader ("simple.frag");
            var vertShader = new VertexShader ("simple.vert");
            var shaderProg = new ShaderProgram (vertShader, fragShader);

            app.SetShaderProgram (shaderProg);

            var msh = new Mesh (1, 0);
            msh.SetVertexBuffer (vbuf);
            msh.SetIndexBuffer (0, ibuf);
            msh.SetShaderAppearance (0, app);

            var unifs = new ShaderUniforms ();
            var id = unifs.AddUniform ("m3g_ModelViewProjection", ShaderVariableType.Mat4, 0);
            unifs.SetObjectBinding (id, msh, ShaderUniforms.GetName (() => msh.ModelViewProjectionMatrix));
            app.AddShaderUniforms (unifs);

            wld.AddChild (msh);
        }


        protected override void OnResize (EventArgs e) {
            base.OnResize (e);

            g3d.SetViewport (ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
        }

        protected override void OnUpdateFrame (FrameEventArgs e) {
            base.OnUpdateFrame (e);

            if (Keyboard[Key.Escape])
                Exit ();
        }

        protected override void OnRenderFrame (FrameEventArgs e) {
            base.OnRenderFrame (e);

            g3d.BindTarget (null);

            
            g3d.Render (wld);

            g3d.ReleaseTarget ();

            SwapBuffers ();
        }

        static void Main (string[] args) {

            using (Program prog = new Program ()) {
                prog.Run (30);
            }
        }
    }
}
